package com.atguigu.netty.simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.NettyRuntime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NettyServer {

    private static Logger logger = LoggerFactory.getLogger(Thread.currentThread().getClass());

    public static void main(String[] args) throws InterruptedException {

        System.out.println("cpu 核数：" + NettyRuntime.availableProcessors());

        // 创建BossGroup 和WorkerGroup
        // 1 bossGroup只处理连接请求，workerGroup负责真正的业务处理
        // 2 两个都是无限循环
        // 3 bossGroup workerGroup含有子线程（NioEventLoop）的个数，默认是实际CPU个数乘以2
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(8);

        try {
            // 创建服务器启动对象，配置参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            // 使用链式编程进行设置
            serverBootstrap.group(bossGroup, workerGroup) // 设置两个线程组
                    .channel(NioServerSocketChannel.class)     // 使用NioServerSocketChannel作为服务端的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列等待连接的个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动连接状态
//                    .handler(new NettyServerHandler()) //handler对应bossGroup，childHandler对应workerGroup
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 创建通道初始化对象（匿名对象）
                        // 向pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 可以用集合管理SocketChannel，在推送消息等业务时，可以将业务加入到各个channel对应的NioEventLoop的taskQueue或scheduleTaskQueue
                             logger.info("客户端socketChannel hashcode： " + ch.hashCode());
                            ch.pipeline().addLast(new NettyServerHandler());

                        }
                    });    // 给workerGroup的EventLoop 对应的管道设置处理器

             logger.info("........服务端 is ready.........");

            // 绑定端口，并且同步，返回ChannelFuture对象
            // 直到绑定结果返回，才会继续后面的执行，否则阻塞当前线程
            ChannelFuture channelFuture = serverBootstrap.bind(6668).sync();
            logger.info("........服务端启动中.........，线程状态{}",Thread.currentThread().getState());
            // 给ChannelFuture注册监听器，监控关心的事件
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                         logger.info("服务端绑定端口 6668 成功");
                    } else {
                         logger.info("服务端绑定端口 6668 失败");
                    }
                }
            });
            logger.info("........服务添加channel事件.........，线程状态{}",Thread.currentThread().getState());
            // 对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
            logger.info("........服务端closeFuture.........");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
